from django.shortcuts import render
from rest_framework.views import APIView
from random import randint
from django_redis import get_redis_connection
from meiduo_mail.libs.yuntongxun.sms import CCP
from rest_framework.response import Response
import logging
from rest_framework import status
from . import constants
from django.views.generic import View
from django.http import HttpResponse
from rest_framework.generics import CreateAPIView
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from django.conf import settings
from rest_framework.permissions import IsAuthenticated

from celery_tasks.sms.tasks import send_sms_code
from meiduo_mail.utils.captcha.captcha import captcha
from users.models import User


# Create your views here.
logger = logging.getLogger('django')  # 创建日志输出器 ？



# 请求路径/uses/user_id/password/
class FindPassWord4View(APIView):
    """两种请求方式对应两种更改密码"""
    def post(self, request, user_id):
        password = request.data.get('password')
        password2 = request.data.get('password2')
        # 解密token 检查user_id 是否一致
        try:
            token = request.data.get('access_token')
            # 解密，取值mobile
            serializer = Serializer(settings.SECRET_KEY, 24 * 60 * 60)
            data = serializer.loads(token)
            user_id1 = data.get('user_id')
            if user_id1 == int(user_id):
                user = User.objects.get(id=user_id)
                user.set_password(password)  # 对密码进行加密
                user.save()
        except Exception as e:
            return Response({'message': '修改密码失败'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
        else:
            return Response({'message':'OK'})


    # def put(self, request, user_id):
    #     permission_classes = [IsAuthenticated]
    #     password = request.data.get('password')
    #     password2 = request.data.get('password2')
    #     old_password = request.data.get('old_password')
    #     # 解密token 检查user_id 是否一致
    #     try:
    #         user = User.objects.get(id=user_id)
    #         if user.check_password(old_password) and password2==password:
    #             user.set_password(password)  # 对密码进行加密
    #             user.save()
    #     except Exception as e:
    #         return Response({'message': '修改密码失败'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
    #     else:
    #         return Response({'messge':'密码修改成功'})


# 请求路径 accounts/liangang/password/token/?sms_code=508773
class FindPassWord3View(APIView):
    """找回密码第二步， 验证短信验证码"""
    def get(self, request,username):
        sms_code = request.query_params.get('sms_code')
        mobile = User.objects.get(username=username).mobile
        user_id = User.objects.get(username=username).id
        redis_conn = get_redis_connection('verify_codes')

        real_sms_code = redis_conn.get('sms_%s' % mobile)

        if sms_code != real_sms_code.decode():
            return Response(status=400)
        # 生成token
        serializer = Serializer(settings.SECRET_KEY, 24 * 60 * 60)
        # 包装一个要加密的字典
        data = {'username': username,'mobile': mobile, 'user_id':user_id}
        # 调用dumps 方法加密
        token = serializer.dumps(data).decode()

        # 构建响应数据
        data = {
            'user_id':user_id,
            'access_token': token,
        }
        return Response(data)



# 请求路径 /sms_code/
class FindPassWord2View(APIView):
    """找回密码第二步 发送短信验证码"""
    def get(self, request):
        token = request.query_params.get('access_token')
        # 解密，取值mobile
        serializer = Serializer(settings.SECRET_KEY, 24 * 60 * 60)
        data = serializer.loads(token)
        mobile = data.get('mobile')

        # 创建连接到redis 数据库
        redis_conn = get_redis_connection('verify_codes')

        # 60秒内不允许重发短信
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        if send_flag:
            return Response({"message":"发送短信过于频繁"}, status=status.HTTP_400_BAD_REQUEST)

        # 生成和发送短信验证码
        sms_code = "%06d" % randint(0, 999999)
        logger.debug(sms_code)

        # 创建redis 管道对象
        pl = redis_conn.pipeline()

        # 保存短信验证码
        redis_conn.setex('send_flag_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
        pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
        print(sms_code)

        # 保存发送短信验证码的标记
        #redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
        pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)

        # 执行管道
        pl.execute()

        send_sms_code.delay(mobile, sms_code)

        # 返回响应结果
        return Response({'message':'OK'})



# 请求路径/accounts/liangang/sms/token/?text=FPFM&image_code_id=a1dca68c-893c-4cb0-85ae-d8efe14b3b02
class FindPassWord1View(CreateAPIView):
    """找回密码第一步 检测用户名和图片验证码"""
    def get(self,request,username):
        image_code_id = request.query_params.get('image_code_id')
        image_code = request.query_params.get('text')
        redis_conn = get_redis_connection('imageCode')
        username = username
        # 查询用户名
        count = User.objects.filter(username=username).count()

        if count > 1:
            return Response(status=404)
        # 查询图片验证码并检测
        real_image_code = None
        try:
            real_image_code = redis_conn.get("ImageCode_%s" % image_code_id)
        except Exception as e:
                raise
        if not real_image_code:
            return Response(status=404)

        #real_image_code有值： 将图片验证码从redis中删除（防止多次使用同一个验证码来进行多次验证码）
        else:
            try:
                redis_conn.delete("CODEID_%s" % image_code_id)
            except Exception as e:
                raise

        #对比用户添加的图片验证码值和真实的图片验证码值是否一致
        if image_code.lower() != real_image_code.decode().lower():
            # 3.2.1 不相等：提示图片验证码填写错误，如果错误码是404,再次生成一张新的图片验证码即可
            return Response(status=400)

        # 查询该账号的对应手机号
        mobile = User.objects.get(username=username).mobile

        # 生成token
        serializer = Serializer(settings.SECRET_KEY, 24 * 60 * 60)
        # 包装一个要加密的字典
        data = {'username': username,'mobile': mobile}
        # 调用dumps 方法加密
        token = serializer.dumps(data).decode()

        # 构建响应数据
        data = {
            'mobile':mobile,
            'username':username,
            'access_token': token,
        }
        return Response(data)



class GetImageCodeView(View):
    """获取图片验证码"""
    def get(self, request, image_code_id):
        # 1.获取当前图片编号id
        #code_id = request.args.get('image_code_id')
        code_id = image_code_id
        redis_conn = get_redis_connection('imageCode')
        # 2.生成验证码
        name, text, image = captcha.generate_captcha()
        try:
            # 保存当前生成的图片验证内容
            redis_conn.setex('ImageCode_' + code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
        except Exception as e:
            raise HttpResponse({'error_message':'图片验证码存储失败'})

        # # 返回响应内容
        return HttpResponse(image)



class SMSCodeView(APIView):
    """发送短信验证码"""
    def get(self, request, mobile):

        # 校验UUID
        text = request.query_params.get('text')
        image_code_id = request.query_params.get('image_code_id')
        if text:
            redis_conn = get_redis_connection('imageCode')
            real_image_code = redis_conn.get('ImageCode_' + image_code_id)
            if text != real_image_code.decode():
                return Response({'message': '验证码错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 创建连接到redis 数据库
        redis_conn = get_redis_connection('verify_codes')

        # 60秒内不允许重发短信
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        if send_flag:
            return Response({"message":"发送短信过于频繁"}, status=status.HTTP_400_BAD_REQUEST)

        # 生成和发送短信验证码
        sms_code = "%06d" % randint(0, 999999)
        logger.debug(sms_code)

        # 创建redis 管道对象
        pl = redis_conn.pipeline()

        # 保存短信验证码
        redis_conn.setex('send_flag_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
        pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
        print(sms_code)

        # 保存发送短信验证码的标记
        #redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
        pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)

        # 执行管道
        pl.execute()


        # 集成容联通讯发送短信验证码
        # 此处注释， 改为异步发送短信
        # CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], 1)
        # 触发异步任务（让发送短信不阻塞主线程）
        # send_sms_code(mobile, sms_code)
        send_sms_code.delay(mobile, sms_code)

        # 返回响应结果
        return Response({'message':'OK'})



